package basic;

import java.util.HashMap;

/**
 * &	与	两个位都为1时，结果才为1
 * |	或	两个位都为0时，结果才为0
 * ^	异或	两个位相同为 0，相异为 1.异或的特点是两个数都会影响最后的结果。
 *
 * @see HashMap#hash (h = key.hashCode()) ^ (h >>> 16)——减少hash冲突
 * ~	取反	0变1，1变0
 * <<	左移	各二进位全部左移若干位，高位丢弃，低位补0
 * >>	右移	各二进位全部右移若干位，如果该数为正，则高位补0，若为负数，则高位补1；
 * >>> 无符号右移 也叫逻辑右移，即若该数为正，则高位补0，而若该数为负数，则右移后高位同样补0
 */

public class BitOperation {

    public static void main(String[] args) {
        long phone1 = 15269281320L;
        long phone2 = 15269281321L;
        // 两个位相同为0，相异为1
        System.out.println("phone1 ^ phone2::" + (phone1 ^ phone2));
        System.out.println("phone1 ^ phone2::" + (phone1 ^ phone1));

        int total = 24;
        int num = 8;
        System.out.println(total & ~num);
        System.out.println(total - num);


        System.out.println(Integer.toBinaryString(2));
        System.out.println("++++");
        System.out.println(Integer.toBinaryString(-2));
        System.out.println("11111111111111111111111111111110".length());
        System.out.println(2 ^ 0);

        System.out.println(-1L ^ (-1L << 5));

        // 负数的求模运算
        int negative = -12;
        // -2
        System.out.println(negative % 10);
        xor();

        // -1 的原码 1000 00001， 反码 1111 1110，补码 1111 1111
        // 补码整体右移 1 位，高位补1，还是 1111 1111
        System.out.println("-1 >> 1 = " + (-1 >> 1));
        System.out.println("-1 << 1 = " + (-1 << 1));
        // -2 的原码 1000 0010， 反码 1111 1101，补码 1111 1110
        // 补码 1111 1110 整体右移 1 位，高位补1， 1111 1111
        System.out.println(-2 >> 1);

        // Integer.MIN_VALUE 补码为 10000000 00000000 00000000 00000000
        // Integer.MIN_VALUE 没有原码和反码，只有补码
        System.out.println("Integer.MIN_VALUE >> 31 = "+ (Integer.MIN_VALUE >> 31)); // >> 考虑符号位，符号位不移动，后面的位数移动，高位补1，移动后，仍然表示为一个补码。结果 -1
        System.out.println("Integer.MIN_VALUE >>> 31 = " + (Integer.MIN_VALUE >>> 31)); // >>> 就是不用考虑符号位，直接整体右移，高位补0，移动后，看做二进制表示的数字。结果 1

        // 相当于移动了一整圈，1 又回到最高位。 Integer.MIN_VALUE >>> x 相当于 Integer.MIN_VALUE >>> (x % 32)
        System.out.println((Integer.MIN_VALUE >>> 32) == Integer.MIN_VALUE);

    }

    static void xor() {
        boolean flag0 = false;
        boolean flag1 = true;
        System.out.println(flag0 + " ^ " + flag0 + ": " + (flag0 ^ flag0));
        System.out.println(flag0 + " ^ " + flag1 + ": " + (flag0 ^ flag1));
        System.out.println(flag1 + " ^ " + flag0 + ": " + (flag1 ^ flag0));
        System.out.println(flag1 + " ^ " + flag1 + ": " + (flag1 ^ flag1));
        System.out.println("总结：异或的两边不一样就是true，两边一样的话就是 false");
        // 异或具有 归零律、恒等律、交换律 、结合律、自反
        // 归零律 a ^ a = 0
        // 恒等律 a ^ 0 = a
        // 交换律 a ^ b = b ^ a
        // 结合律 a ^ b ^ c = a ^ (b ^ c)
        // 自反律 a ^ b ^ a = b (这是异或最具魅力的特性，可以理解为 两者异或的结果 与 异或的任意对象 再次异或 就可以求出另一个异或对象)
        // 异或的自反律是 土耳其Erdal Arikan教授发现极化码（Polar Codes）的关键
        int a = 0;
        int b = 1;
        int c = 2;
        System.out.println("归零律 a ^ a =" + (a ^ a));
        System.out.println("恒等律 a ^ 0 = " + (a ^ 0));
        System.out.println("交换律 a ^ b = b ^ a " + ((a ^ b) == (b ^ a)));
        System.out.println("结合律 a ^ b ^ c = a ^ (b ^ c) " + ((a ^ b ^ c) == (a ^ (b ^ c))));
        System.out.println("自反律 a ^ b ^ a =  " + (a ^ b ^ a));
    }
}
